/**
 * 
 * 文件名：MsgFormatter.java
 *
 * 功能：对日志信息进行格式化
 *
 *
 * 变更记录：
 *
 * 创建者：陈保毕
 * 
 * 日期：2016年3月23日
 */
package com.hpjz.common.log;

import java.util.HashMap;
import java.util.Map;




public class MsgFormatter {
     static final char DELIM_START = '{';
     static final char DELIM_STOP = '}';
     static final String DELIM_STR = "{}";
     private static final char ESCAPE_CHAR = '\\';
     
     
     public static final String arrayFormat(final String messagePattern,final Object[] array){
    	 if (messagePattern==null||array==null) {
			return null;
		}
    	 
    	 int i = 0;
    	 int j = 0;
    	 final int sbufAppendSize = 50;
    	 StringBuffer sbuf = new StringBuffer(messagePattern.length()+sbufAppendSize);
    	 
    	 int L;
    	 for (L = 0; L < array.length; L++) {
			j = messagePattern.indexOf(DELIM_STR,i);
			if (j==-1) {
				if (i==0) {
				 return	messagePattern;
				} else {
					sbuf.append(messagePattern.substring(i, messagePattern.length()));
                  return sbuf.toString();
				}
			} else {
                 if (isEscapedDelimeter(messagePattern, j)) {
					if (!isDoubleEscaped(messagePattern,j)) {
						L--;
						sbuf.append(messagePattern.substring(i,j-1));
						sbuf.append(DELIM_START);
						i=j+1;
					} else {
						sbuf.append(messagePattern.substring(i,j-1));
                       deeplyAppendParameter(sbuf,array[L],new HashMap());
                       i = j+2;
					}
				} else {
					sbuf.append(messagePattern.substring(i,j));
                    deeplyAppendParameter(sbuf,array[L],new HashMap());
                    i = j+2;
				}
			}
		}
    	 
    	 //append the characters following the last {} pair
    	 sbuf.append(messagePattern.substring(i, messagePattern.length()));
    	/* if (L<array.length-1) {
			return sbuf.toString();
		} else {

		}*/
    	 return sbuf.toString();
     }
     
     
     private static void  deeplyAppendParameter(StringBuffer sbuf,Object o,Map seenMap){
    	 if (o==null) {
			sbuf.append("null");
			return;
		}
    	if (!o.getClass().isArray()) {
			safeObjectAppend(sbuf,o);
		} else {
            //需要判断是否是原生数组
			if(o instanceof boolean[]){
				booleanArrayAppend(sbuf,(boolean[])o);
			}else if(o instanceof byte[]){
				byteArrayAppend(sbuf,(byte[])o);
			}else if(o instanceof char[]){
				charArrayAppend(sbuf,(char[])o);
			}else if(o instanceof short[]){
				shortArrayAppend(sbuf,(short[])o);
			}else if(o instanceof int[]){
				intArrayAppend(sbuf,(short[])o);
			}else if(o instanceof long[]){
				longArrayAppend(sbuf,(short[])o);
			}else if(o instanceof double[]){
				doubleArrayAppend(sbuf,(short[])o);
			}else{
				objectArrayAppend(sbuf,(Object[])o,seenMap);
			}
		} 
    	 
     }
     
     private static void doubleArrayAppend(StringBuffer sbuf, short[] a) {
    	 sbuf.append('[');
         final int len = a.length;
         for (int i = 0; i < len; i++) {
				sbuf.append(a[i]);
				if (i!=len-1) {
					sbuf.append(", ");
				}
			}
        sbuf.append(']'); 
		
	}


	private static void longArrayAppend(StringBuffer sbuf, short[] a) {
    	 sbuf.append('[');
         final int len = a.length;
         for (int i = 0; i < len; i++) {
				sbuf.append(a[i]);
				if (i!=len-1) {
					sbuf.append(", ");
				}
			}
        sbuf.append(']'); 
	}


	private static void intArrayAppend(StringBuffer sbuf, short[] a) {
    	 sbuf.append('[');
         final int len = a.length;
         for (int i = 0; i < len; i++) {
				sbuf.append(a[i]);
				if (i!=len-1) {
					sbuf.append(", ");
				}
			}
        sbuf.append(']'); 
	}


	private static void shortArrayAppend(StringBuffer sbuf, short[] a) {
    	 sbuf.append('[');
         final int len = a.length;
         for (int i = 0; i < len; i++) {
				sbuf.append(a[i]);
				if (i!=len-1) {
					sbuf.append(", ");
				}
			}
        sbuf.append(']'); 
	}


	private static void charArrayAppend(StringBuffer sbuf, char[] a) {
    	 sbuf.append('[');
         final int len = a.length;
         for (int i = 0; i < len; i++) {
				sbuf.append(a[i]);
				if (i!=len-1) {
					sbuf.append(", ");
				}
			}
        sbuf.append(']'); 
	}


	private static void byteArrayAppend(StringBuffer sbuf, byte[] a) {
            sbuf.append('[');
            final int len = a.length;
            for (int i = 0; i < len; i++) {
				sbuf.append(a[i]);
				if (i!=len-1) {
					sbuf.append(", ");
				}
			}
           sbuf.append(']'); 
	}


	private static void booleanArrayAppend(StringBuffer sbuf, boolean[] a) {
    	 sbuf.append('[');
    	 final int len = a.length;
    	 for (int i = 0; i < len; i++) {
			sbuf.append(a[i]);
			if (i!=len-1) {
				sbuf.append(", ");
			}
		}
		sbuf.append(']');
	}


	private static void safeObjectAppend(StringBuffer sbuf,Object o){
    	 try {
			String oAsString = o.toString();
			sbuf.append(oAsString);
		} catch (Exception t) {
			System.err.println("MsgFormatter:Failed toString() invacation on an Object of type ["+
		     o.getClass().getName()+"]");
			t.printStackTrace();
			sbuf.append("[FAILED toString()]");
		}
     }
     
	private static void objectArrayAppend(StringBuffer sbuf, Object[] a,
			Map seenMap) {
		sbuf.append('[');
		if (!seenMap.containsKey(a)) {
			seenMap.put(a, null);
			final int len = a.length;
			for (int i = 0; i < len; i++) {
				deeplyAppendParameter(sbuf, a[i], seenMap);
				if (i != len - 1) {
					sbuf.append(", ");
				}
				seenMap.remove(a);
			}
		} else {
			sbuf.append("...");
		}

		sbuf.append(']');

	}
     
	
	
     
     /*
      * 判断是否是转义分割符
      * @return
      */
     private static boolean isEscapedDelimeter(String messagePattern,int delimeterStartIndex){
    	  if (delimeterStartIndex==0) {
			return false;
		}
    	  char potentialEscape = messagePattern.charAt(delimeterStartIndex-1);
    	  return potentialEscape == ESCAPE_CHAR;
     }
     
     
     /**
      * 判断是否是双转义字符
      * @param messagePattern
      * @param delimeterStartIndex
      * @return
      */
     private static boolean isDoubleEscaped(String messagePattern,int delimeterStartIndex){
    	 final int idxStart = 2;
    	 return delimeterStartIndex>=idxStart&&
    			 messagePattern.charAt(delimeterStartIndex-idxStart)==ESCAPE_CHAR;
     }
}
